// 发行版脚本，增加用户交互提示
// 在脚本开头定义日志文件路径
// 打开文件对话框让用户选择文件夹
var folder = Folder.selectDialog("请选择日志文件保存的文件夹：");
if (folder) {
    // 构造文件路径（使用 File 类）
    var LOG_FILE = new File(folder.fsName + "/psd_script_log.txt");
    
    // 如果文件存在，删除文件
    if (LOG_FILE.exists) {
        LOG_FILE.remove();
    }
    
    // 输出日志路径
    log("日志文件已保存到：" + decodeURI(LOG_FILE.path));
} else {
    alert("未选择文件夹");
}

var CONFIG = {
    LAYER_RULES: {
        FACE: /(face|脸部)/i,  
        EXPRESSION: /(表情|喜|怒|哀|忧|哭|闭眼|笑|生气|委屈|泪)/i,
        FACE_REF: /face_ref/i // 参考图层后缀
    },
    EXPORT: {
        QUALITY: 100,
        TRANSPARENCY: true
    }
};

//////////////////////////////
// 主流程（三步选择模式）
//////////////////////////////
//////////////////////////////
// 改进的错误处理模块
//////////////////////////////
function main() {
    try {
        var startTime = new Date();
        log("===== 立绘自动处理脚本 Written By Cairo =====");

        var refFile = selectReferenceFile();
        var inputFolder = selectInputFolder();
        var outputFolder = selectOutputFolder();

        var refDoc = openDocument(refFile);
        var refData = buildReferenceMap(refDoc); // 增加有效性检查

        processAllFiles(inputFolder, outputFolder, refData);
        refDoc.close(SaveOptions.DONOTSAVECHANGES);

        log("处理完成！总耗时: " + ((Date.now() - startTime) / 1000).toFixed(1) + "秒");
    } catch (e) {
        showErrorDialog("致命错误：" + e.message + "\n堆栈：" + (e.stack || "不可用"));
    }
}

//////////////////////////////
// 文件选择模块
//////////////////////////////
function selectReferenceFile() {
    var file = File.openDialog("请选择参考PSD文件", "*.psd", false);
    if (!file) throw new Error("必须选择参考文件");
    return file;
}

function selectInputFolder() {
    var folder = Folder.selectDialog("请选择包含PSD的输入文件夹");
    if (!folder) throw new Error("必须选择输入目录");
    return folder;
}

function selectOutputFolder() {
    var folder = Folder.selectDialog("请选择输出根目录");
    if (!folder) throw new Error("必须选择输出目录");
    return folder;
}

// 打开文档（优化异常处理）
function openDocument(file) {
    if (!file.exists) throw new Error("文件不存在: " + file.fsName);
    var doc = app.open(file);
    doc.activeLayer = doc.layers[0]; // 解锁首层
    return doc;
}

//////////////////////////////
// 核心处理逻辑
//////////////////////////////
function processAllFiles(inputFolder, outputRoot, refData) {
    var files = inputFolder.getFiles("*.psd");
    for (var i = 0; i < files.length; i++) {
        var file = files[i];
        logDebug("处理文件: " + decodeURI(file.name));
        if (file instanceof File) {
            try {
                processCharacterFile(file, outputRoot, refData);
            } catch (e) {
                logError('文件处理失败：' + decodeURI(file.name) + '\n原因：' + e.message);
            }
        }
    }
}

//////////////////////////////
// 改进的参考图层加载模块
//////////////////////////////
function buildReferenceMap(refDoc) {
    var map = {};
    var refCount = 0;

    log("开始扫描参考文档图层结构：");
    traverseLayers(refDoc, function (layer) {
        try {
            // logDebug("正在检测图层: " + layer.name);

            // 判断是否为 face_ref 图层
            if (CONFIG.LAYER_RULES.FACE_REF.test(layer.name)) {
                // 强制单位转换
                if (app.preferences.rulerUnits !== Units.PIXELS) {
                    app.preferences.rulerUnits = Units.PIXELS;
                    app.activeDocument.rulerUnits = Units.PIXELS;
                }

                // 计算坐标和尺寸
                var center = getLayerCenter(layer);
                if (center.width < 10 || center.height < 10) {
                    throw new Error("尺寸过小(" + center.width + "x" + center.height + "px)");
                }

                map.face = {
                    center: [center.x, center.y],
                    size: { width: center.width, height: center.height }
                };
                refCount++;
                log("成功加载参考: face_ref");
            }
        } catch (e) {
            logError("处理失败：" + layer.name + "原因：" + e.message);
        }
    });

    if (!map.face) {
        throw new Error("参考文件中未找到 face_ref图层！");
    }
    return map;
}



function processCharacterFile(psdFile, outputRoot, refData) {
    var doc = openDocument(psdFile);
    try {
        // 准备输出路径
        var outputPath = createOutputStructure(outputRoot, psdFile.name);

        // 处理单个文档，并导出裁剪好的PNG
        copyToFixedCanvas(doc, refData, outputPath);

    } finally {
        // 关闭原始文档
        doc.close(SaveOptions.DONOTSAVECHANGES);
        app.purge(PurgeTarget.ALLCACHES);
    }
}


//////////////////////////////
// 图层处理增强模块
//////////////////////////////

// new
function copyToFixedCanvas(originalDoc, refData, outputPath) {
    // 步骤1：计算目标脸部中心点中心点位置和宽度
    var targetCenterX = refData.face.center[0];
    var targetCenterY = refData.face.center[1];
    var targetWidth = refData.face.size.width;
    var targetHeight = refData.face.size.height;


    // 步骤2：计算原文件中脸部中心点位置
    // 2.1 查找 face 图层
    var faceLayers = findLayerByRegex(originalDoc, CONFIG.LAYER_RULES.FACE);
    if (!faceLayers) {
        alert("在待处理文档中未找到脸部图层！");
        return;
    }
    // 只能有一个face图层
    var faceLayer = faceLayers[0];

    // 2.2 计算脸部中心点位置
    var faceCenter = getLayerCenter(faceLayer);
    var faceCenterX = faceCenter.x;
    var faceCenterY = faceCenter.y;
    var faceWidth = faceCenter.width;
    var faceHeight = faceCenter.height;
    var scaleFactorW = (targetWidth / faceWidth) * 100;
    var scaleFactorH = (targetHeight / faceHeight) * 100;
    // 选择较小的缩放比例
    var scaleFactor = Math.min(scaleFactorW, scaleFactorH);


    // 步骤3：合并表情上方的可见图层，并进行复制、平移、缩放
    // 3.1 解锁所有图层
    unlockAllLayers(originalDoc);

    // 3.2 合并表情上方的所有可见图层
    var aboveLayer = mergeVisibleLayersAbove(originalDoc, CONFIG.LAYER_RULES.EXPRESSION);
    if (aboveLayer) {
        log("合并成功，合并后的图层：" + aboveLayer.name);
    } else {
        log("未能找到匹配的图层或未进行合并");
    }

    // 3.3 计算aboveLayer图层的必要数据
    // 中心点位置
    var aboveCenter = getLayerCenter(aboveLayer);
    var aboveCenterX = aboveCenter.x;
    var aboveCenterY = aboveCenter.y;
    // 两者之间的相对距离
    var FaceAboveOffsetX = faceCenterX - aboveCenterX;
    var FaceAboveOffsetY = faceCenterY - aboveCenterY;

    // 3.4 将aboveLayer复制到新文档中
    // 新建新文档
    var newWidth = 1280;
    var newHeight = 720;
    var newDoc = app.documents.add(
        newWidth,
        newHeight,
        300, // 分辨率
        "temp_export",
        NewDocumentMode.RGB,         // 使用 RGB 模式
        DocumentFill.TRANSPARENT     // 初始填充为透明
    );
    // **确保原始文档是前台，复制**
    app.activeDocument = originalDoc;
    aboveLayer.duplicate(newDoc, ElementPlacement.PLACEATBEGINNING);
    // **确保新文档是前台**
    app.activeDocument = newDoc;
    // 新文档中的第一个图层即为复制的图层
    var newAboveLayer = newDoc.artLayers[0];

    // 3.5 调整图层位置和尺寸
    moveAndResizeLayer(newAboveLayer, FaceAboveOffsetX, FaceAboveOffsetY, targetCenterX, targetCenterY, scaleFactor);
    logDebug("above图层已缩放");
    newAboveLayer.visible = false;


    // 步骤4：合并所有可见图层
    // **确保原始文档是前台**
    app.activeDocument = originalDoc;
    // 4.1 合并所有可见图层，多级文件夹不影响合并
    try {
        originalDoc.mergeVisibleLayers();
        logDebug("所有可见图层已合并");
    } catch (e) {
        logError("合并图层失败：" + e.message);
        return;
    }

    // 4.2 计算合并图层的必要数据
    // 新生成的图层通常会成为文档中的第一个图层，有隐藏图层不影响合并
    //var mergedLayer = originalDoc.artLayers[0];
    var mergedLayer = originalDoc.activeLayer;
    var mergedCenter = getLayerCenter(mergedLayer);
    var mergedCenterX = mergedCenter.x;
    var mergedCenterY = mergedCenter.y;
    // 两者之间的相对距离
    var FaceMergedOffsetX = faceCenterX - mergedCenterX;
    var FaceMergedOffsetY = faceCenterY - mergedCenterY;

    // 4.3 将合并图层复制到新文档中  
    mergedLayer.duplicate(newDoc, ElementPlacement.PLACEATBEGINNING);
    // **确保新文档是前台**
    app.activeDocument = newDoc;
    // 新文档中的第一个图层即为复制的图层
    var newLayer = newDoc.artLayers[0];
    // 4.4 调整图层位置和尺寸
    moveAndResizeLayer(newLayer, FaceMergedOffsetX, FaceMergedOffsetY, targetCenterX, targetCenterY, scaleFactor);
    logDebug("总合并图层已缩放");


    // 步骤5：导出全身立绘
    var fileName = originalDoc.name.replace(/\.psd$/i, ".png")
    var folder = outputPath.full;
    exportPNG(newDoc, fileName, folder);


    // 步骤6：导出表情
    // 查找所有表情图层
    var expressionLayers = findLayerByRegex(originalDoc, CONFIG.LAYER_RULES.EXPRESSION);
    if (expressionLayers) {
        for (var i = 0; i < expressionLayers.length; i++) {
            // **还原原始文档为前台**
            app.activeDocument = originalDoc;
            expressionLayers[i].duplicate(newDoc, ElementPlacement.PLACEATBEGINNING);
            // **确保新文档是前台**
            app.activeDocument = newDoc;
            var expressionLayer = newDoc.artLayers[0];
            // 隐藏其他图层
            hideAllLayers(newDoc);
            // 显示表情图层
            expressionLayer.visible = true;
            // 调整图层位置和尺寸
            moveAndResizeLayer(expressionLayer, 0, 0, targetCenterX, targetCenterY, scaleFactor)
            // 调整图层顺序,将 expressionLayer 移动到 newAboveLayer 之下
            expressionLayer.move(newAboveLayer, ElementPlacement.PLACEAFTER);
            newAboveLayer.visible = true;
            // 导出表情图层
            var fileName = expressionLayer.name + '.png';
            var folder = outputPath.expressions;
            exportPNG(newDoc, fileName, folder);
        }
    }


    // 步骤7：关闭新文档
    newDoc.close(SaveOptions.DONOTSAVECHANGES);
    // **还原原始文档为前台**
    app.activeDocument = originalDoc;
}


//////////////////////////////
// 工具函数增强版
//////////////////////////////

// 递归的图层遍历函数
function traverseLayers(doc, callback) {
    function scanLayers(layers, depth) { // 移除默认参数
        // logDebug("当前深度: " + depth + ", 图层数: " + layers.length);
        depth = depth || 0; // 传统默认值写法

        for (var i = layers.length - 1; i >= 0; i--) {
            var layer = layers[i];
            if (layer.typename === "LayerSet") {
                scanLayers(layer.layers, depth + 1); // 递归调用
            }
            callback(layer);
        }
    }
    scanLayers(doc.layers, 0); // 初始depth传0
}

// 解锁所有图层
function unlockAllLayers(doc) {
    traverseLayers(doc, function (layer) {
        try {
            // 如果图层有 allLocked 属性，则解除所有锁定
            if (layer.allLocked) {
                layer.allLocked = false;
            }
            // 如果图层有 locked 属性，则解除锁定
            if (layer.locked) {
                layer.locked = false;
            }
        } catch (e) {
            // 有些图层可能不支持解锁操作，忽略错误
            logError("无法解锁图层 " + layer.name + "，原因：" + e.message);
        }
    });
}


// 隐藏所有图层
function hideAllLayers(doc) {
    traverseLayers(doc, function (layer) {
        try {
            layer.visible = false;
        } catch (e) {
            logError("无法隐藏图层 " + layer.name + "，原因：" + e.message);
        }
    });
}

// 根据正则表达式寻找图层
function findLayerByRegex(doc, regex) {
    var foundLayers = []; // 存储匹配到的图层
    traverseLayers(doc, function (layer) {
        if (regex.test(layer.name)) {
            foundLayers.push(layer); // 存入匹配的图层
        }
    });
    return foundLayers; // 返回匹配的图层，若无匹配返回 null
}

// 计算图层的中心点位置
function getLayerCenter(layer) {
    var bounds = layer.bounds;
    var x1 = Number(bounds[0]);
    var y1 = Number(bounds[1]);
    var x2 = Number(bounds[2]);
    var y2 = Number(bounds[3]);
    return {
        x: (x1 + x2) / 2,
        y: (y1 + y2) / 2,
        width: x2 - x1,
        height: y2 - y1
    };
}


// 缩放图层并保持锚点位置不变
function resizeLayerWithAnchor(layer, scaleFactor, anchorX, anchorY) {
    var originalBounds = layer.bounds;
    var originalX = Number(originalBounds[0]);
    var originalY = Number(originalBounds[1]);

    // 计算锚点在图层内的相对坐标（相对于左上角）
    var anchorLocalX = anchorX - originalX;
    var anchorLocalY = anchorY - originalY;

    // 计算缩放后的新位置，使锚点位置不变
    var newX = anchorX - anchorLocalX * (scaleFactor / 100);
    var newY = anchorY - anchorLocalY * (scaleFactor / 100);

    // 直接调整图层位置和尺寸：使用 TOPLEFT 作为缩放锚点
    layer.resize(scaleFactor, scaleFactor, AnchorPosition.TOPLEFT, ResampleMethod.BICUBICSHARPER);
    // 平移：应使用 newX - originalX, newY - originalY
    layer.translate(newX - originalX, newY - originalY);
}

// 判断图层是否为空
function isLayerEmpty(layer) {
    // 这里需要根据你的图层数据结构和场景具体判断图层是否为空
    // 例如，检查图层的高度和宽度是否为零，或者像素值是否全透明

    // 示例：假设层的 bounds 属性为空即视为空层
    var bounds = layer.bounds;
    if (bounds[0] === 0 && bounds[1] === 0 && bounds[2] === 0 && bounds[3] === 0) {
        return true;
    }

    return false;
}


// 合并目标图层上方的所有可见图层（修正图层组移动问题）
function mergeVisibleLayersAbove(doc, targetRegex) {
    var targetLayer = null;
    var layersAbove = [];
    var found = false;

    // 遍历所有图层（traverseLayers 是自下而上遍历）
    traverseLayers(doc, function (layer) {
        if (!found && targetRegex.test(layer.name)) {
            targetLayer = layer;
            found = true;
            return; // 找到目标层后开始记录上方图层
        }

        // visible可以正确处理组隐藏图层
        if (found && layer.visible) {
            layersAbove.unshift(layer); // 逆序插入保持原有层级
        }
    });

    if (!targetLayer) {
        alert("未找到匹配的目标图层！");
        return null;
    }

    if (layersAbove.length === 0) {
        alert("目标图层上方没有可见图层，无需合并！");
        return null;
    }

    // 创建临时组（放在目标图层上方以保证合并位置正确）
    var tempGroup = doc.layerSets.add();
    tempGroup.move(targetLayer, ElementPlacement.PLACEBEFORE);

    // 反向遍历以保持图层顺序
    for (var i = layersAbove.length - 1; i >= 0; i--) {
        var layer = layersAbove[i];
        try {
            // **如果是普通图层（artLayer），移动到组内**
            if (layer.typename === "ArtLayer") {
                layer.move(tempGroup, ElementPlacement.INSIDE);
            }
            // **如果是图层组（LayerSet），不处理**
            // else if (layer.typename === "LayerSet") {

            // }
        } catch (e) {
            logError("移动图层失败：" + layer.name + "，原因：" + e.message);
        }
    }

    // 合并临时组
    try {
        tempGroup.merge();
        return doc.activeLayer;
    } catch (e) {
        logError("合并失败：" + e.message);
        return null;
    }
}

// function isEffectivelyVisible(layer) {
//     // 检查图层本身及所有父级文件夹的 visible 属性
//     while (layer) {
//         if (!layer.visible) return false;
//         layer = layer.parent; // 若 layer.parent 存在，则继续检查
//         // 注意：在顶层，parent 可能是文档对象，需做判断
//         if (layer.typename === "Document") break;
//     }
//     return true;
// }



// 统一的平移缩放函数
function moveAndResizeLayer(newLayer, FaceLayerOffsetX, FaceLayerOffsetY, targetCenterX, targetCenterY, scaleFactor) {
    // 计算复制到新文档中的图层的中心点位置
    var newCenter = getLayerCenter(newLayer);
    var newCenterX = newCenter.x;
    var newCenterY = newCenter.y;
    // 根据之前计算的相对距离求出新文件中脸部中心点位置
    var newFaceCenterX = newCenterX + FaceLayerOffsetX;
    var newFaceCenterY = newCenterY + FaceLayerOffsetY;
    // 计算出应平移的距离
    var offsetX = targetCenterX - newFaceCenterX;
    var offsetY = targetCenterY - newFaceCenterY;
    // 平移
    newLayer.translate(offsetX, offsetY);
    // 缩放
    resizeLayerWithAnchor(newLayer, scaleFactor, targetCenterX, targetCenterY);
}



// 导出PNG
function exportPNG(doc, fileName, folder) {
    var exportFile = new File(folder.fsName + "/" + fileName);
    var options = new ExportOptionsSaveForWeb();
    options.format = SaveDocumentType.PNG;
    // 设置 PNG24 格式（默认是 PNG8，设为false表示24）
    options.PNG8 = false;
    options.transparency = CONFIG.EXPORT.TRANSPARENCY;
    options.quality = CONFIG.EXPORT.QUALITY;

    doc.exportDocument(exportFile, ExportType.SAVEFORWEB, options);
    log("导出PNG: " + fileName);
}

// 构建导出目录
function createOutputStructure(root, fileName) {
    var baseName = fileName.replace(/\.psd$/i, "");
    var paths = {
        full: new Folder(root.fsName + "/" + baseName + "/完整立绘/"),
        expressions: new Folder(root.fsName + "/" + baseName + "/表情/")
    };

    var folders = [paths.full, paths.expressions];
    for (var i = 0; i < folders.length; i++) {
        var folder = folders[i];
        if (!folder.exists) {
            folder.create();
            logDebug("创建目录：" + folder.fsName);
        }
    }

    return paths;
}


//////////////////////////////
// 日志系统增强版
//////////////////////////////
function log(msg) {
    var f = new File(LOG_FILE);
    f.open("a"); // 追加模式
    f.writeln("[LOG] " + new Date().toLocaleString() + " - " + msg);
    f.close();
}

function logDebug(msg) {
    log("[DEBUG] " + msg);
}

function logWarning(msg) {
    log("[WARNING] " + msg);
}

function logError(msg) {
    log("[ERROR] " + msg);
}

function showErrorDialog(msg) {
    alert(msg, "错误", true);
    log(msg, "错误", true);
}




// 执行入口
main();